/**
 * 
 */
package ua.lviv.franko.solvers.oneDimention;

import java.util.ArrayList;

import ua.lviv.franko.integration.GaussQuadrature;
import ua.lviv.franko.integration.IFunction1D;
import ua.lviv.franko.integration.Quadrature;
import ua.lviv.franko.solvers.ElementMatrix;
import ua.lviv.franko.solvers.IElement1D;

/**
 * @author marko
 * 
 */
public class LinearElement implements IElement1D {

	public static int				QuadraturePointsNumber	= 20;

	// problem data
	protected EquationParameters	eParams;
	// element number starting from 0
	protected int					elNumber;
	// element information
	protected double				left;
	protected double				right;
	// results
	protected ElementMatrix			data;

	public LinearElement(EquationParameters eParams, double left, double right, int elNumber) {
		this.elNumber = elNumber;
		this.eParams = eParams;
		this.left = left;
		this.right = right;
	}

	@Override
	public double calculate(double x, double[] vals) {
		double h = right - left;
		return (right - x) / h * vals[elNumber] + (x - left) / h * vals[elNumber + 1];
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateAll()
	 */
	@Override
	public void generateAll() {
		Quadrature gau = new GaussQuadrature(QuadraturePointsNumber);
		// final EquationParameters finalEP = this.eParams;

		ArrayList<Integer> pos = new ArrayList<Integer>();
		pos.add(this.elNumber);
		pos.add(this.elNumber + 1);
		data = new ElementMatrix(pos);

		final double h = right - left;
		//
		data.vector[0] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				return eParams.f.calculate(x) * ((right - x) / h);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

		data.vector[1] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				return eParams.f.calculate(x) * ((x - left) / h);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

		data.matrix[0][0] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				double femFuncVal = (right - x) / h;// (x - left)/h;
				double femFuncDerivatyVal = (-1.0) / h;

				return eParams.p.calculate(x) * (femFuncDerivatyVal * femFuncDerivatyVal) + eParams.w.calculate(x) * (femFuncDerivatyVal * femFuncVal) + eParams.q.calculate(x)
						* (femFuncVal * femFuncVal);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

		data.matrix[1][1] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				double femFuncVal = (x - left) / h;
				double femFuncDerivatyVal = (1.0) / h;

				return eParams.p.calculate(x) * (femFuncDerivatyVal * femFuncDerivatyVal) + eParams.w.calculate(x) * (femFuncDerivatyVal * femFuncVal) + eParams.q.calculate(x)
						* (femFuncVal * femFuncVal);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

		data.matrix[1][0] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				double femFuncVal1 = (right - x) / h;// (x - left)/h;
				double femFuncDerivatyVal1 = (-1.0) / h;
				double femFuncVal2 = (x - left) / h;
				double femFuncDerivatyVal2 = (1.0) / h;

				return eParams.p.calculate(x) * (femFuncDerivatyVal1 * femFuncDerivatyVal2) + eParams.w.calculate(x) * (femFuncDerivatyVal1 * femFuncVal2) + eParams.q.calculate(x)
						* (femFuncVal1 * femFuncVal2);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

		data.matrix[0][1] = gau.integrate(left, right, new IFunction1D() {

			@Override
			public double calculate(double x) {
				double femFuncVal2 = (right - x) / h;// (x - left)/h;
				double femFuncDerivatyVal2 = (-1.0) / h;
				double femFuncVal1 = (x - left) / h;
				double femFuncDerivatyVal1 = (1.0) / h;

				return eParams.p.calculate(x) * (femFuncDerivatyVal1 * femFuncDerivatyVal2) + eParams.w.calculate(x) * (femFuncDerivatyVal1 * femFuncVal2) + eParams.q.calculate(x)
						* (femFuncVal1 * femFuncVal2);
			}

			@Override
			public double calculateDerivaty(double x) {
				return 0;
			}
		});

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateFe()
	 */
	@Override
	public double[] generateFe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generatePe()
	 */
	@Override
	public double[][] generatePe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateQe()
	 */
	@Override
	public double[][] generateQe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateWe()
	 */
	@Override
	public double[][] generateWe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#getAll()
	 */
	@Override
	public ElementMatrix getAll() {

		return this.data;
	}

	@Override
	public int lastNumber() {
		return this.elNumber + 1;
	}

}
